
<template>

  <div v-if="renderPreview" class="base-item">
    <template v-if=" [
          'input',
          'textarea',
          'time',
          'number',
          'rate',
          'switch',
          'slider'
        ].includes(record.type)">
      <span class="base-item-span" v-if="record.options.prepend" v-html="transformAppend(record.options.prepend)">
      </span>
      <span class="base-item-span" v-if="!loading">{{ models[record.model] }} </span>
      <span class="base-item-span" v-if="record.options.append" v-html="transformAppend(record.options.append)">
      </span>
    </template>
    <template v-if="record.type == 'date' || record.type == 'datePicker'">
      <span v-if="record.options.range && models[record.model] instanceof Array">
        {{ models[record.model].join(' ~ ') }}
      </span>
      <span v-else>
         {{ models[record.model] }}
      </span>
    </template>

    <n-l-state
        v-else-if="record.type == 'state'"
        v-model="models[record.model]"
        :renderPreview="renderPreview"
        :models="models"
        :record="record"
        :config="formConfig"
        :parentDisabled="disabled"
        :disabled="disabled || record.options.disabled"
    />
    <template v-else-if="[
          'radio',
          'checkbox',
          'select',
          'cascader'
        ].includes(record.type)">
      {{ models[record.model + '_label'] }}
    </template>
    <template v-else-if="[
          'uploadImg',
          'uploadFile'
        ].includes(record.type)">


      <FileUpload
          v-if="record.type == 'uploadImg'"
          :style="`width:${record.options.width}`"
          v-model="models[record.model]"
          accept="image/*"
          :list-type="record.options.listType"
          :readOnly="true"
          :record="record"
      />

      <FileUpload
          v-else
          :style="`width:${record.options.width}`"
          v-model="models[record.model]"
          :readOnly="true"
          :record="record"
      />
    </template>

    <template v-else-if="customList.includes(record.type)">
      <customComponent
          :models="models"
          :record="record"
          :disabled="disabled || record.options.disabled"
          :renderPreview="true"
          @change="handleChange($event, record.model)"
      />
    </template>

    <template v-else>
      {{ '' }}
    </template>


  </div>
  <div v-else class="base-item">


    <Input

        :style="`width:${record.options.width}`"
        v-if="record.type === 'input'"
        :disabled="dynamicDisabled"
        :placeholder="record.options.placeholder"
        :type="record.options.type"
        :clearable="record.options.clearable"
        :maxlength="record.options.maxLength > 0 ? record.options.maxLength : null"
        @on-change="handleChange($event, record.model)"
        v-model="models[record.model]"
        :size="formConfig ? formConfig.size : null"
    >
      <span v-if="record.options.prepend" slot="prepend" v-html="transformAppend(record.options.prepend)">

      </span>
      <span v-if="record.options.append" slot="append" v-html="transformAppend(record.options.append)">

      </span>
    </Input>

    <Input
        v-model="models[record.model]"
        type="textarea"
        :style="`width:${record.options.width}`"
        v-else-if="record.type === 'textarea'"
        :disabled="dynamicDisabled"
        :placeholder="record.options.placeholder"
        :clearable="record.options.clearable"
        :maxlength="record.options.maxLength > 0 ? record.options.maxLength : null"
        :rows="record.options.rows"
        :show-word-limit="record.options.maxLength > 0 && record.options.maxLength > 10"
        @on-change="handleChange($event, record.model)"
        :size="formConfig ? formConfig.size : null"
    />


    <template v-else-if="record.type === 'number'">
      <div :style="`width:${record.options.width}`" class="el-input-number-diaplay">

        <InputNumber
            :class="record.options.append ? 'el-input-number__append' : null"
            v-model="models[record.model]"
            :style="`width:100%;float:left;`"
            :min="
            record.options.min || record.options.min === 0
              ? record.options.min
              : -Infinity
          "
            :max="
            record.options.max || record.options.max === 0
              ? record.options.max
              : Infinity
          "
            :disabled="dynamicDisabled"
            :step="record.options.step"
            :precision="
            record.options.precision > 50 ||
            (!record.options.precision && record.options.precision !== 0)
              ? null
              : record.options.precision
          "
            controls-position="right"
            :placeholder="record.options.placeholder"
            @on-change="handleChange($event, record.model)"
            :size="formConfig ? formConfig.size : null"
        />
        <div class="el-input-group__append el-input-number-group__append " v-if="record.options.append"
             v-html="transformAppend(record.options.append)">

        </div>
      </div>

    </template>



    <template v-else-if="record.type === 'select' ">
      <Select
          v-model="checkList"
          :value-key="itemProp.value"
          :style="`width:${record.options.width}`"
          v-if="record.options.multiple"
          :remote="record.options.onlineSearch && record.options.showSearch"
          :remote-method="remoteMethod"
          :placeholder="record.options.placeholder"
          :filterable="record.options.showSearch"
          :disabled="dynamicDisabled"
          :clearable="record.options.clearable"
          multiple
          @on-clear="clearChange"
          @on-change="handleChange($event, record.model ,  true)"
          :size="formConfig ? formConfig.size : null"
      >
        <template
            v-for="(item,index) in ((record.options.dynamic == 1 && record.options.remoteFunc) || (record.options.dynamic == 2 && record.options.dictType) ? checkValues : record.options.options)">
          <Option
              :key="item[itemProp.value] + index"
              :label="item[itemProp.label]"
              :value="item[itemProp.value]"
              v-if="itemVisible(item)"
          > {{ item[itemProp.label] }}
          </Option>
        </template>
      </Select>
      <Select
          v-else
          v-model="models[record.model]"
          :style="`width:${record.options.width}`"
          :value-key="itemProp.value"
          :remote="record.options.onlineSearch && record.options.showSearch"
          :remote-method="remoteMethod"
          :placeholder="record.options.placeholder"
          :filterable="record.options.showSearch"
          :disabled="dynamicDisabled"
          :clearable="record.options.clearable"
          @on-clear="clearChange"
          @on-change="handleChange($event, record.model , true)"
          :size="formConfig ? formConfig.size : null"
      >
        <template
            v-for="(item,index) in ((record.options.dynamic == 1 && record.options.remoteFunc) || (record.options.dynamic == 2 && record.options.dictType) ? checkValues : record.options.options)">
          <Option
              :key="item[itemProp.value] + index"
              :label="item[itemProp.label]"
              :value="item[itemProp.value]"
              v-if="itemVisible(item)"
          > {{ item[itemProp.label] }}
          </Option>
        </template>
      </Select>
    </template>


    <CheckboxGroup
        v-else-if="record.type === 'checkbox'"
        v-model="checkList"
        :disabled="dynamicDisabled"
        :placeholder="record.options.placeholder"
        @on-change="handleChange($event, record.model)"
        :size="formConfig ? formConfig.size : null"
    >
      <template
          v-for="(checkitem,index) in  ( (record.options.dynamic == 1 && record.options.remoteFunc) || (record.options.dynamic == 2 && record.options.dictType) ? checkValues : record.options.options)">
        <Checkbox :label="checkitem[itemProp.value]" :key="checkitem[itemProp.value] + index"
                  v-if="itemVisible(checkitem)">
          {{ checkitem[itemProp.label] }}
        </Checkbox>
      </template>
    </CheckboxGroup>


    <RadioGroup
        v-model="models[record.model]"
        v-else-if="record.type === 'radio'"
        :disabled="dynamicDisabled"
        :placeholder="record.options.placeholder"
        @on-change="handleChange($event, record.model)"
        :size="formConfig ? formConfig.size : null"
    >
      <template
          v-for="(radioitem,index) in ((record.options.dynamic == 1 && record.options.remoteFunc) || (record.options.dynamic == 2 && record.options.dictType) ? checkValues : record.options.options)">
        <Radio :label="radioitem[itemProp.value]" :key="radioitem[itemProp.value] + index"
               v-if="itemVisible(radioitem)">
          {{ radioitem[itemProp.label] }}
        </Radio>
      </template>
    </RadioGroup>


    <template v-else-if="record.type === 'date'">

      <DatePicker
          v-if="record.options.range"
          :style="`width:${record.options.width}`"
          v-model="models[record.model]"
          align="right"
          type="daterange"
          :clearable="record.options.clearable"
          :disabled="dynamicDisabled"
          :placeholder="record.options.rangeStartPlaceholder + ' ~ ' + record.options.rangeEndPlaceholder"
          :format="record.options.format"
          :size="formConfig ? formConfig.size : null"
          @on-change="handleChange($event, record.model)">
      </DatePicker>
      <DatePicker
          v-else
          :style="`width:${record.options.width}`"
          v-model="models[record.model]"
          align="right"
          type="date"
          :clearable="record.options.clearable"
          :disabled="dynamicDisabled"
          :placeholder="record.options.placeholder"
          :format="record.options.format"
          :size="formConfig ? formConfig.size : null"
          @on-change="handleChange($event, record.model)">
      </DatePicker>

    </template>


    <template v-else-if="record.type === 'datePicker'">

      <DatePicker
          v-if="record.options.range"
          :style="`width:${record.options.width}`"
          v-model="models[record.model]"
          align="right"
          type="datetimerange"
          :clearable="record.options.clearable"
          :disabled="dynamicDisabled"
          :placeholder="record.options.rangeStartPlaceholder + ' ~ ' + record.options.rangeEndPlaceholder"

          :format="record.options.format"
          :size="formConfig ? formConfig.size : null"
          @on-change="handleChange($event, record.model)">
      </DatePicker>
      <DatePicker
          v-else
          :style="`width:${record.options.width}`"
          v-model="models[record.model]"
          align="right"
          type="datetime"
          :clearable="record.options.clearable"
          :disabled="dynamicDisabled"
          :placeholder="record.options.placeholder"
          :format="record.options.format"
          :value-format="record.options.format"
          :size="formConfig ? formConfig.size : null"
          @on-change="handleChange($event, record.model)">
      </DatePicker>

    </template>



    <TimePicker
        v-else-if="record.type === 'time'"
        :style="`width:${record.options.width}`"
        v-model="models[record.model]"
        @on-change="handleChange($event, record.model)"
        :clearable="record.options.clearable"
        :disabled="dynamicDisabled"
        :placeholder="record.options.placeholder"
        :format="record.options.format"
        :size="formConfig ? formConfig.size : null"
        :value-format="record.options.format">
    </TimePicker>



    <Rate
        v-model="models[record.model]"
        :style="`width:${record.options.width}`"
        v-else-if="record.type === 'rate'"
        :count="record.options.max"
        :disabled="dynamicDisabled"
        :placeholder="record.options.placeholder"
        :allowHalf="record.options.allowHalf"
        :size="formConfig ? formConfig.size : null"
        @on-change="handleChange($event, record.model)"

    />

    <Slider
        v-else-if="record.type === 'slider'"
        v-model="models[record.model]"
        :style="`width:${record.options.width}`"
        :disabled="dynamicDisabled"
        :min="record.options.min"
        :max="record.options.max"
        :show-input="record.options.showInput"
        :step="record.options.step"
        :marks="sliderMarks"
        :size="formConfig ? formConfig.size : null"
        @on-change="handleChange($event, record.model)"

    />


    <FileUpload
        v-else-if="record.type === 'uploadImg'"
        :style="`width:${record.options.width}`"
        :disabled="dynamicDisabled"
        v-model="models[record.model]"
        :record="record"
        accept="image/*"
        :list-type="record.options.listType"
        :multiple="record.options.multiple"
        :action="record.options.action"
        :limit="record.options.limit"
        @change="handleChange($event, record.model)"

    />

    <template v-else-if="record.type === 'uploadFile'">

      <FileUpload
          :style="`width:${record.options.width}`"
          :disabled="dynamicDisabled"
          v-model="models[record.model]"
          :multiple="record.options.multiple"
          :action="record.options.action"
          :record="record"
          :accept="record.options.accept"
          :limit="record.options.limit"
          @change="handleChange($event, record.model)"

      />
    </template>


    <Cascader
        v-else-if="record.type === 'cascader'"
        ref="cascader"
        v-model="checkList"
        :data="(record.options.dynamic == 1 && record.options.remoteFunc ? checkValues : record.options.options)"
        :style="`width:${record.options.width}`"
        :placeholder="record.options.placeholder"
        :filterable="record.options.showSearch"
        :disabled="dynamicDisabled"
        :clearable="record.options.clearable"
        :props="itemProp"
        :size="formConfig.size"
        @on-change="handleChange($event, record.model)"

    />



    <i-switch
        v-model="models[record.model]"
        v-else-if="record.type === 'switch'"
        :active-text="record.options.activeText"
        :inactive-text="record.options.inactiveText"
        :disabled="dynamicDisabled"
        @on-change="handleChange($event, record.model)"
        :size="formConfig ? formConfig.size : null"
    />

    <n-l-state
        v-else-if="record.type == 'state'"
        :style="`width:${record.options.width}`"
        v-model="models[record.model]"
        :renderPreview="renderPreview"
        :models="models"
        :record="record"
        :config="formConfig"
        :parentDisabled="disabled"
        :disabled="disabled || record.options.disabled"
    />

    <customComponent
        :models="models"
        v-else-if="customList.includes(record.type)"
        :record="record"
        :disabled="dynamicDisabled"
        :formConfig="formConfig"
        :renderPreview="renderPreview"
        @change="handleChange($event, record.model)"
        :size="formConfig ? formConfig.size : null"
    />
  </div>
</template>
<script>
import cloneDeep from 'lodash/cloneDeep';
import request from '../utils/request.js';
import FileUpload from './upload';
import {dynamicFun, dateFormater} from '../utils';
import CustomComponent from './custom';
import NLState from './state';

export default {
  name: 'FormItemBase',
  data() {
    return {
      loading: false,
      checkList: [],
      checkValues: [],
      itemProp: {
        children: 'children',
        value: 'value',
        label: 'label',
        multiple: this.record.options.multiple,

      },

      remoteUrl: '',


      localFilter: [],
      remoteFilter: {},
    };
  },
  props: {


    record: {
      type: Object,
      required: true,
    },

    formConfig: {
      type: Object,
      required: false,
    },

    models: {
      type: Object,
      required: true,
    },
    disabled: {
      type: Boolean,
      default: false,
    },

    renderPreview: {
      type: Boolean,
      default: false,
    },

    isDragPanel: {
      type: Boolean,
      default: false,
    },
  },
  components: {
    FileUpload, CustomComponent, NLState,
  },
  inject: {
    customComponents: {
      from: 'customC',
      default: () => [],
    },
    ngConfig: {
      from: 'ngConfigC',
      default: () => ({}),
    },
  },
  computed: {
    sliderMarks() {

      if (this.record.type !== 'slider' || !this.record.options.marks || this.record.options.marks.length == 0) {
        return null;
      }

      let p = {};

      this.record.options.marks.forEach(t => {

        p[t.value] = t.label;

      });

      return p;

    },
    customList() {

      if (this.customComponents) {
        return this.customComponents.map(item => item.type);
      } else {
        return [];
      }
    },
    linkageData() {
      if (!this.isDragPanel && this.record.options.linkage) {
        const linkData = this.record.options.linkData;
        if (!linkData) {
          return null;
        }

        let vs = [];
        for (const ld of lindData) {
          if (ld.model) {
            vs.push(this.models[ld.model]);

          }
        }
        return vs;

      }
      return null;
    },
    modelsRecord() {
      return this.models[this.record.model];
    },
    dynamicDisabled() {
      if (this.disabled) {
        return true;
      }

      if (this.record.options.disabled) {
        if (this.record.options.dynamicDisabled) {
          if (this.record.options.dynamicDisabledValue) {
            const script = this.record.options.dynamicDisabledValue;

            const fvalue = dynamicFun(script, this.models, this.data);
            return fvalue;
          } else {
            return true;
          }
        } else {
          return true;
        }

      }
      return false;
    },

    dynamicOption() {


      if (!this.isDragPanel || !['select', 'radio', 'checkbox'].includes(this.record.type)) {
        return null;
      }
      if (this.record.options.dynamic == 0) {
        return null;
      }
      if (this.record.options.dynamic == 1) {
        return this.record.options.dynamic + this.record.options.remoteFunc + this.record.options.dataPath + this.record.options.remoteValue + this.record.options.remoteLabel;
      } else if (this.record.options.dynamic == 2) {
        return this.record.options.dynamic + this.record.options.dictType;
      }

      return null;
    },
  },
  watch: {
    checkList: {
      handler(val, oldVal) {
        this.$set(this.models, this.record.model, val);
      },
      deep: true,
    },
    checkValues: {
      handler(val, oldVal) {
        const value = this.models[this.record.model];
        this.handleChange(value, this.record.model, 1);
      },
      deep: true,
    },
    linkageData: {
      handler(val, oldVal) {
        if (this.record.options.linkage) {
          const linkData = this.record.options.linkData;
          if (!linkData) {
            return;
          }

          let localScript = [];
          let remoteQuery = {};
          for (const ld of linkData) {
            if (ld.vtype == 1) {
              localScript.push(ld.script);
            } else if (ld.vtype == 2
                && this.record.options.dynamic == 1 && this.record.options.remoteFunc
                && ld.queryKey && ld.queryValue) {
              const queryValue = dynamicFun(ld.queryValue, this.models);

              remoteQuery[ld.queryKey] = queryValue;

            }
          }

          this.localFilter = localScript;
          this.remoteFilter = remoteQuery;

          if ((this.record.type === 'select' && this.record.options.multiple) || this.record.type === 'checkbox') {
            this.checkList = [];
          } else {
            this.$set(this.models, this.record.model, null);
          }


          if (this.remoteFilter) {
            this.getRemoteData();
          }

        }

      },
      deep: true,
    },
    modelsRecord: {
      handler(val, oldVal) {
        if (this.record.type == 'checkbox' || (this.record.type == 'select' && this.record.options.multiple)) {

          if (val instanceof Array) {
            this.checkList = val;
          }

        }

      },
      deep: true,
    },
    dynamicOption: {
      handler(val, oldVal) {
        this.initDynamicValue();
      },
      deep: true,
    },
  },
  methods: {
    transformAppend(append) {
      if (append && (append.indexOf('return') >= 0 || append.indexOf('$') >= 0)) {
        const script = append;

        const fvalue = dynamicFun(script, this.models);

        return fvalue;
      }
      return append;
    },
    remoteMethod(query) {
      let queryParam = this.record.options.onlineParams;
      queryParam = queryParam.replace('$', query);

      let url = this.record.options.remoteFunc;

      if (url.indexOf('?') >= 0) {
        url += '&' + queryParam;
      } else {
        url += '?' + queryParam;
      }

      this.remoteUrl = url;

      this.getRemoteData();
    },
    getRemoteData() {

      const objectPath = require('object-path');

      const dataPath = this.record.options.dataPath;

      request({
        url: this.remoteUrl,
        method: 'get',
        params: {
          ...this.remoteFilter,
        },
      }).then((data) => {
        if (data) {
          const rdata = objectPath.get(data, dataPath);

          this.checkValues = rdata;
        }
      });
    },
    dynamicVisible(script, item) {
      const func = script.indexOf('return') >= 0 ? '{' + script + '}' : 'return (' + script + ')';
      const Fn = new Function('$', '$item', func);
      return Fn(this.models, item);
    },
    itemVisible(item) {
      if (this.isDragPanel || !this.localFilter || this.localFilter.length == 0) {
        return true;
      }

      for (const lf of this.localFilter) {
        const v = this.dynamicVisible(lf, item);

        if (!v) {
          return false;
        }
      }
      return true;
    },

    clearChange() {
      if (!this.record.options.clearCb) {
        return;
      }

      const cbScript = this.record.options.clearCb;
      const func = '{' + cbScript + '}';
      const Fn = new Function('$', 'data', func);
      Fn(this.models, this.data);
    },
    handleChange(value, key, type) {
      if (this.record.type == 'date' || this.record.type == 'datePicker') {
        this.$set(this.models, key, value);
      }
      this.$emit('change', value, key);

      if (['select', 'radio', 'checkbox', 'cascader'].includes(this.record.type)) {
        let labels = [];
        let datas = this.record.options.dynamic > 0 ? this.checkValues : this.record.options.options;
        if (!datas) {
          datas = [];
        }

        if (this.record.type == 'cascader') {
          let as = [];
          if (!this.itemProp.multiple) {
            as = [value];
          } else {
            as = value;
          }

          const checkNodes = this.$refs.cascader.getCheckedNodes();
          for (const v of as) {
            const fs = checkNodes.filter(t => t.path == v);

            if (fs && fs.length > 0) {
              const label = fs[0].pathLabels;
              if (label && label.length > 0) {
                labels.push(label.join('/'));
              }
            }

          }


        } else {
          let as = [];

          if (!(value instanceof Array)) {
            as = [value];
          } else {
            as = value;
          }

          for (const v of as) {
            const fs = datas.filter(t => t[this.itemProp.value] == v);
            if (fs && fs.length > 0) {
              const label = fs[0][this.itemProp.label];

              labels.push(label);
            }

          }

        }

        const modelLabel = this.record.model + '_label';
        this.$set(this.models, modelLabel, labels.join(','));


        if (type && this.record.options.selectCb) {
          const cvalues = (this.record.options.dynamic == 1 && this.record.options.remoteFunc ? this.checkValues : this.record.options.options);

          const fs = cvalues.filter(t => t[this.itemProp.value] == value);

          if (fs && fs.length > 0) {
            const select = fs[0];

            this.$nextTick(() => {
              const scriptFunc = this.record.options.selectCb;
              const func = '{' + scriptFunc + '}';
              const Fn = new Function('$', '$select', func);

              Fn(this.models, select);


            });

          }


        }


      }
    },
    initDynamicValue() {
      if (this.record.options.dynamic == 1 && this.record.options.remoteFunc) {
        const url = this.record.options.remoteFunc;
        this.remoteUrl = url;


        this.getRemoteData();


        this.itemProp.label = this.record.options.remoteLabel;
        this.itemProp.value = this.record.options.remoteValue;
        this.itemProp.children = this.record.options.remoteChildren;
      } else if (this.record.options.dynamic == 2 && this.record.options.dictType) {

        if (this.ngConfig && this.ngConfig.dict && this.ngConfig.dict.length > 0) {
          const fsDict = this.ngConfig.dict.filter(t => t.type == this.record.options.dictType);
          this.checkValues = cloneDeep(fsDict);

          this.itemProp.label = 'label';
          this.itemProp.value = 'value';
          this.itemProp.children = 'children';
        }


      }
    },
  },
  mounted() {

    if (this.record.options.cbColumn && !this.isDragPanel) {
      this.loading = true;
      const value = this.data[this.record.options.cbColumn];e
      this.$set(this.models, this.record.model, value);
      this.loading = false;
      return;
    }

    this.initDynamicValue();


    if (this.models && Object.prototype.hasOwnProperty.call(this.models, this.record.model) && this.models[this.record.model]) {
      let modelValue = this.models[this.record.model];
      if (this.record.type == 'checkbox' || this.record.type == 'cascader' || (
          this.record.type == 'select' && this.record.options.multiple
      )) {
        if (!(modelValue instanceof Array)) {
          modelValue = modelValue.split(',');
          this.$set(this.models, this.record.model, modelValue);
        }
        this.checkList = modelValue;
      }
      return;
    }

    let defaultValue = this.record.options.defaultValue;
    if (defaultValue != null) {
      if (this.record.type == 'checkbox' || this.record.type == 'cascader') {
        this.checkList = defaultValue;
      } else {
        if ((this.record.type == 'date' || this.record.type == 'time' || this.record.type == 'datePicker') && defaultValue == 'now') {
          defaultValue = dateFormater(new Date(), this.record.options.format);

        }
        this.$set(this.models, this.record.model, defaultValue);
      }

      this.handleChange(defaultValue, this.record.model);
    }

    if (!this.isDragPanel) {
      if (!Object.prototype.hasOwnProperty.call(this.models, this.record.model)) {

        if (this.record.type == 'checkbox' || this.record.type == 'cascader'
            || (this.record.type == 'select' && this.record.options.multiple)) {

          this.$set(this.models, this.record.model, []);
        } else if (this.record.type == 'number') {

          this.$set(this.models, this.record.model, null);
        } else {

          this.$set(this.models, this.record.model, '');
        }
      } else if (this.record.type == 'checkbox' || this.record.type == 'cascader'
          || (this.record.type == 'select' && this.record.options.multiple)) {

        const mv = this.models[this.record.model];


        if (typeof mv == 'string') {
          if (mv == '') {
            this.$set(this.models, this.record.model, []);
          } else {
            const mvs = mv.split(',');
            this.$set(this.models, this.record.model, mvs);
          }

        }

      }

    }


  },
};
</script>

